
#include "JniObject.h"

#include <map>
#include <string>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>


static JavaVM *     g_JavaVM;
jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
    JNIEnv* env = NULL;
    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_4) != JNI_OK)
        return JNI_ERR;
    g_JavaVM = vm;
    JniObjectNativeMethodHelper::RegisterAllNatives(env);
    return JNI_VERSION_1_4;
}

void JNI_OnUnload(JavaVM* vm, void* reserved)
{
}


REGISTER_CLASS_CREATOR(JniObject);


JniObject::JniObject()
    : mEnv(NULL)
    , mThiz(NULL)
    , mCreateAndBind(NULL)
{
}

void JniObject::init(JNIEnv* env, jobject thiz)
{
    mEnv = env;
    mThiz = thiz;

    printf("thiz = %p\n", thiz);
    printf("____________________________________________ this = %p\n", this);
    jfieldID id = env->GetFieldID(env->GetObjectClass(thiz), "native_instance", "J");
    jlong ins = reinterpret_cast<jlong>((JniObject*)this);
    printf("____________________________________________ ins = %lx\n", ins);
    env->SetLongField(thiz, id, ins);

    initJavaMethods(env);
}


JniObject* JniObject::getObjectFromJava(jobject thiz)
{
    return getObjectFromJava(mEnv, thiz);
}

JniObject* JniObject::getObjectFromJava(JNIEnv* env, jobject thiz)
{
    jfieldID id = env->GetFieldID(env->GetObjectClass(thiz), "native_instance", "J");
    jlong ins = env->GetLongField(thiz, id);

    printf("thiz = %p\n", thiz);
    printf("____________________________________________ ins = %lx\n", ins);
    JniObject* obj = reinterpret_cast<JniObject*>(ins);

    printf("____________________________________________ obj = %p\n", obj);
    return obj;
}


JniObject::~JniObject()
{
}

void JniObject::createAndBindJavaObject(JNIEnv* env)
{
    printf("mEnv = %p, mThiz = %p, mCreateAndBind = %p\n", mEnv, mThiz, mCreateAndBind);
    jclass clazz = (jclass)(env->FindClass(getAlteredClassName().c_str()));
    printf("class = %s, clazz = %p\n", getAlteredClassName().c_str(), clazz);
    if (clazz) {
        if (!mCreateAndBind) {
            mCreateAndBind = env->GetStaticMethodID(clazz, "onCreateAndBindJavaObject", "(Ljava/lang/String;J)V");
        }
        jstring jclassname = env->NewStringUTF(getCurrentClassName());
        // printf("_________________ this = %p\n", this);
        env->CallStaticVoidMethod(clazz, mCreateAndBind, jclassname, reinterpret_cast<long>((JniObject*)(this)));
        env->DeleteLocalRef(jclassname);

    }
}

char * JniObject::alterClassName(char* className)
{
    char * p = className;
    while (*p != '\0') {
        if (*p == '.')
            *p = '/';
        p++;
    }
    return className;
}

std::string JniObject::getAlteredClassName()
{
    char classname[1024];
    strncpy(classname, getClassName(), sizeof(classname));
    alterClassName(classname);
    return std::string(classname);
}

void JniObject::_create_and_bind_object(JNIEnv* env, jobject thiz, jstring clazzname)
{
    const char* className = env->GetStringUTFChars(clazzname, 0);
    if (className) {
        printf("create class by name: %s\n", className);
        JniObject* obj = JniObjectFactory::createByClassName(className);
        // printf("obj = %p\n", obj);
        if (obj) {
            obj->init(env, thiz);
        }
        env->ReleaseStringUTFChars(clazzname, className);
    }
}

void JniObject::_bind_object(JNIEnv* env, jobject thiz, jlong oo)
{
    JniObject* obj = reinterpret_cast<JniObject*>(oo);
    // printf("_________________ obj = %p\n", obj);
    obj->init(env, thiz);
}


